﻿using Module.FlowChart.Logic;
using Module.FlowChart.Model;
using Module.FlowChart.View;
using System;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Windows.Forms;

/// <summary>
/// 流程图绘制界面基类
/// </summary>
namespace Module.FlowChart.RunAble.View
{
    internal abstract class ViewManager_FCBase : ViewManager
    {
        [DllImport("user32.dll", CharSet = CharSet.Auto)]
        static extern short GetAsyncKeyState(int nVirtKey);
        const int VK_CONTROL = 0x11;
        const int VK_ALT = 0x12;

        public const int LinkAbleCycleR = 10;
        public const int GridWidth = 30;

        protected Size DropDiffer;

        protected ViewManager_Info Info;
        protected virtual ContextMenuStrip Menu_NodeRightClick { get; set; }

        protected override float Scale { get => Info.Scale; set => Info.Scale = value; }
        protected override Point LeftTop { get => Info.LeftTop; set => Info.LeftTop = value; }

        public ViewManager_FCBase(ViewManagerHandles h, Document doc, FCWorkPageBase page, Control container)
            : base(h, doc, page, container)
        {

            Info = new ViewManager_Info();
            Info.Page = page;
            Info.Container = Container;
            Info.Drawed = h.Drawed;
            InitRunner();
            Drawer = CreatPageDrawer();
            InitEvent();
            RefreshItemInWindow();
        }


        #region 获取鼠标状态
        public bool IsPointToLinkAblePosotion(Point realpos, FCNode node, out int anchor, bool linkfrom = true)
        {
            anchor = -1;
            int w = (int)(LinkAbleCycleR * Scale / 2);
            Rectangle rect = node.RealRect;
            if (linkfrom)
            {
                switch (node.Type)
                {
                    case FCNodeType.Terminal:
                        if (node.IsStartNode)
                        {
                            anchor = 3;
                            return Utility.IsInCircular(realpos, new Point(rect.X + rect.Width / 2, rect.Y + rect.Height), w);
                        }
                        return false;
                    case FCNodeType.Assign:
                    case FCNodeType.Label:
                        //允许从四个方向连接
                        if (Utility.IsInCircular(realpos, new Point(rect.X + rect.Width / 2, rect.Y), w))
                        {
                            anchor = 1;
                            return true;
                        }
                        else if (Utility.IsInCircular(realpos, new Point(rect.X + rect.Width, rect.Y + rect.Height / 2), w))
                        {
                            anchor = 2;
                            return true;
                        }
                        else if (Utility.IsInCircular(realpos, new Point(rect.X + rect.Width / 2, rect.Y + rect.Height), w))
                        {
                            anchor = 3;
                            return true;
                        }
                        else if (Utility.IsInCircular(realpos, new Point(rect.X, rect.Y + rect.Height / 2), w))
                        {
                            anchor = 4;
                            return true;
                        }
                        break;
                    case FCNodeType.IF:
                        if (Utility.IsInCircular(realpos, new Point(rect.X + rect.Width, rect.Y + rect.Height / 2), w))
                        {
                            anchor = 2;
                            return true;
                        }
                        else if (Utility.IsInCircular(realpos, new Point(rect.X, rect.Y + rect.Height / 2), w))
                        {
                            anchor = 4;
                            return true;
                        }
                        break;
                    case FCNodeType.IO:
                        ////允许从上下进行连接
                        //if (Utility.IsInCircular(realpos, new Point(rect.X + rect.Width / 2, rect.Y), w))
                        //{//仅允许从上方开始连接
                        //    anchor = 1;
                        //    return true;
                        //}
                        //else
                        if (Utility.IsInCircular(realpos, new Point(rect.X + rect.Width / 2, rect.Y + rect.Height), w))
                        {//仅允许从下方开始连接
                            anchor = 3;
                            return true;
                        }
                        break;
                    default:
                        return false;
                }
            }
            else
            {
                switch (node.Type)
                {
                    case FCNodeType.Terminal:
                        if (!node.IsStartNode)
                        {//仅允许从上方开始连接
                            anchor = 1;
                            return Utility.IsInCircular(realpos, new Point(rect.X + rect.Width / 2, rect.Y), w);
                        }
                        return false;
                    case FCNodeType.Assign:
                    case FCNodeType.Label:
                        //允许从四个方向连接
                        if (Utility.IsInCircular(realpos, new Point(rect.X + rect.Width / 2, rect.Y), w))
                        {
                            anchor = 1;
                            return true;
                        }
                        else if (Utility.IsInCircular(realpos, new Point(rect.X + rect.Width, rect.Y + rect.Height / 2), w))
                        {
                            anchor = 2;
                            return true;
                        }
                        else if (Utility.IsInCircular(realpos, new Point(rect.X + rect.Width / 2, rect.Y + rect.Height), w))
                        {
                            anchor = 3;
                            return true;
                        }
                        else if (Utility.IsInCircular(realpos, new Point(rect.X, rect.Y + rect.Height / 2), w))
                        {
                            anchor = 4;
                            return true;
                        }
                        break;
                    case FCNodeType.IF:
                        //允许从左右和上方进行连接
                        if (Utility.IsInCircular(realpos, new Point(rect.X + rect.Width / 2, rect.Y), w))
                        {
                            anchor = 1;
                            return true;
                        }
                        return false;
                    case FCNodeType.IO:
                        //允许从上下进行连接
                        if (Utility.IsInCircular(realpos, new Point(rect.X + rect.Width / 2, rect.Y), w))
                        {//仅允许从上方开始连接
                            anchor = 1;
                            return true;
                        }
                        return false;
                    default:
                        return false;
                }
            }

            return false;
        }
        public bool IsPointToResizeAblePosition(Point realpos, FCNode node, out int anchor)
        {
            Rectangle rect = node.RealRect;// LinkAbleCycleR
            if ((new Rectangle(rect.X - LinkAbleCycleR / 2, rect.Y - LinkAbleCycleR / 2, LinkAbleCycleR, LinkAbleCycleR)).Contains(realpos))
            {
                anchor = 1;
                return true;
            }
            else if ((new Rectangle(rect.X - LinkAbleCycleR / 2 + rect.Width, rect.Y - LinkAbleCycleR / 2, LinkAbleCycleR, LinkAbleCycleR))
                .Contains(realpos))
            {
                anchor = 2;
                return true;
            }
            else if ((new Rectangle(rect.X - LinkAbleCycleR / 2 + rect.Width, rect.Y + rect.Height - LinkAbleCycleR / 2, LinkAbleCycleR, LinkAbleCycleR))
                .Contains(realpos))
            {
                anchor = 3;
                return true;
            }
            else if ((new Rectangle(rect.X - LinkAbleCycleR / 2, rect.Y + rect.Height - LinkAbleCycleR / 2, LinkAbleCycleR, LinkAbleCycleR))
              .Contains(realpos))
            {
                anchor = 4;
                return true;
            }
            anchor = 0;
            return false;
        }
        public FCNode GetNodeAtPosition(Point realpos, int padx, int pady)
        {
            foreach (var node in Info.Page.Nodes.Values)
            {
                if (!node.IsInWindow)
                    continue;
                if (node.RealRect.X - padx <= realpos.X && realpos.X <= node.RealRect.X + node.RealRect.Width + padx &&
                    node.RealRect.Y - pady <= realpos.Y && realpos.Y <= node.RealRect.Y + node.RealRect.Height + pady)
                {
                    return node;
                }
            }
            return null;
        }
        #endregion

        protected abstract void InitRunner();
        protected abstract PageDrawer CreatPageDrawer();

        private void Onpaint(object sender, PaintEventArgs e)
        {
            if (Handles.IsResizing)
                return;
            Drawer.Refresh(e.Graphics);
        }
        protected virtual void InitEvent()
        {
            //绑定 ListView
            Info.Container.DragDrop += OnDragDrop;
            Info.Container.DragEnter += OnDragEnter;
            Info.Container.AllowDrop = true;
            //绑定鼠标操作
            Info.Container.MouseDown += OnMouseDown;
            Info.Container.MouseMove += OnMouseOver;
            Info.Container.MouseLeave += OnMouseOut;
            Info.Container.MouseUp += OnMouseUp;
            Info.Container.MouseWheel += OnMouseWheel;
            Info.Container.Paint += Onpaint;
        }
        private void BindCandidateList(bool active)
        {
            ListView chartCandidateList = Handles.GetControl("chartCandidateList") as ListView;
            if (active)
            {
                var gs = CreatCandidateListGroups();
                foreach (var g in gs)
                    chartCandidateList.Items.AddRange(g.Items);
                chartCandidateList.Groups.AddRange(gs);
                chartCandidateList.View = System.Windows.Forms.View.LargeIcon;
                chartCandidateList.ItemDrag += chartCandidateList_ItemDrag;
            }
            else
            {
                chartCandidateList.Groups.Clear();
                chartCandidateList.Items.Clear();
                chartCandidateList.ItemDrag -= chartCandidateList_ItemDrag;
            }

        }


        private void OnMouseOver(object sender, MouseEventArgs e)
        {
            Info.MousePosition = new Point(e.X, e.Y);
            if (Info.IsRunning())
            {
                OnMouseOver_Running(sender, e);
            }
            else
            {
                OnMouseOver_NotRunning(sender, e);
            }

        }
        private void OnMouseDown(object sender, MouseEventArgs e)
        {
            if (Info.IsRunning())
            {
                OnMouseDown_Running(sender, e);
            }
            else
            {
                OnMouseDown_NotRunning(sender, e);
            }
        }
        private void OnMouseUp(object sender, MouseEventArgs e)
        {
            if (Info.IsRunning())
            {
                OnMouseUp_Running(sender, e);
            }
            else
            {
                OnMouseUp_NotRunning(sender, e);
            }

        }
        private void OnMouseOut(object sender, EventArgs e)
        {
            if (Info.IsRunning())
            {
                OnMouseOut_Running(sender, e);
            }
            else
            {
                OnMouseOut_NotRunning(sender, e);
            }

        }


        private void OnMouseWheel(object sender, MouseEventArgs e)
        {
            if (GetAsyncKeyState(VK_CONTROL) != 0)
            {
                //point old logic x=oldmousex/oldscale+oldlefttopx
                //point new logic x=newmousex/newscale+newlefttopx
                //使得鼠标所指位置的逻辑位置相同
                //wanted lefttop x=mousex/oldscale+oldlefttopx-mousex/newscale
                float oldscale = Info.Scale;
                Info.Scale += Math.Sign(e.Delta) * 0.1f * Info.Scale;
                Info.Scale = Utility.Limit(Info.Scale, 0.25f, 10f);
                int X = Utility.Limit((int)(LeftTop.X + e.X / oldscale - e.X / Info.Scale), 0, int.MaxValue);
                int Y = Utility.Limit((int)(LeftTop.Y + e.Y / oldscale - e.Y / Info.Scale), 0, int.MaxValue);
                LeftTop = new Point(X, Y);
                SetNeedRedraw();
            }
        }
        protected virtual void OnMouseOver_NotRunning(object sender, MouseEventArgs e)
        {
            if (Info.IsDragingNode || Info.IsLinkingNode || Info.IsResizingNode)
            {
                //todo
                if (Info.IsLinkingNode)
                {
                    FCNode node = GetNodeAtPosition(new Point(e.X, e.Y), (int)(LinkAbleCycleR / 2), (int)(LinkAbleCycleR / 2));
                    int last = Info.CurrentPointTo;
                    Info.CurrentPointTo = node == null ? 0 : node.Id;
                    if (Info.CurrentPointTo != last)
                    {
                        //tocheck
                        SetNeedRedraw(true);
                    }
                }
                else if (Info.IsResizingNode)
                {
                }
            }
            else
            {
                //鼠标没有进行操作  显示锚点，记录信息
                FCNode node = GetNodeAtPosition(new Point(e.X, e.Y), (int)(LinkAbleCycleR / 2), (int)(LinkAbleCycleR / 2));
                int last = Info.CurrentPointTo;
                Info.CurrentPointTo = node == null ? 0 : node.Id;
                if (Info.CurrentPointTo != last)
                {
                    SetNeedRedraw(true);//tocheck
                }
                if (node != null)
                {
                    Info.CanLinkNode = IsPointToLinkAblePosotion(new Point(e.X, e.Y), node, out Info.LinkAnchor);
                    Info.CanResizeNode = !Info.CanLinkNode && IsPointToResizeAblePosition(new Point(e.X, e.Y), node, out Info.ReSizeAnchor);
                    Info.CanDragingNode = !Info.CanLinkNode && !Info.CanResizeNode;
                }
                else
                {
                    Info.CanDragingNode = Info.CanLinkNode = Info.CanResizeNode = false;
                    Info.CanDragWorkSpace = true;
                }

            }
        }
        protected virtual void OnMouseOver_Running(object sender, MouseEventArgs e)
        {

        }
        protected virtual void OnMouseDown_NotRunning(object sender, MouseEventArgs e)
        {
            Info.LastMouseDownTime = DateTime.Now;
            Info.MouseDownNode = Info.CurrentPointTo;
            //开始连线
            if (Info.CanLinkNode)
            {
                Info.IsLinkingNode = true;
                var node = Info.Page.FindNode(Info.CurrentPointTo);
                Info.IsLink1 = (node.Type != FCNodeType.IF || Info.LinkAnchor == 4);
            }
            //开始调整大小
            else if (Info.CanResizeNode)
            {
                Info.IsResizingNode = true;
            }
            //开始拖拽
            else if (Info.CanDragingNode)
            {
                Info.DragStartPoint = new Point(e.X, e.Y);
                Info.IsDragingNode = true;
            }
            //拖拽工作区
            else if (Info.CanDragWorkSpace)
            {
                Info.DragStartPoint = new Point(e.X, e.Y);
                Info.IsDragWorkSpace = true;
            }
            if (Info.CurrentPointTo > 0 && Info.SelectedNode != Info.CurrentPointTo
                || Info.CurrentPointTo <= 0 && Info.SelectedNode > 0)
            {
                Info.SelectedNode = Info.CurrentPointTo;
                if (Info.CurrentPointTo > 0)
                {
                    var node = Info.Page.FindNode(Info.CurrentPointTo);
                    ShowPropertyEditor(node);
                }
                else
                {
                    ShowPropertyEditor(null);
                }
                Drawer.Refresh();
            }

        }
        protected virtual void OnMouseDown_Running(object sender, MouseEventArgs e)
        {

        }
        protected virtual void OnMouseUp_NotRunning(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Right)
            {//右键菜单
                if (Info.CurrentPointTo != 0)
                {
                    Menu_NodeRightClick.Show(Info.Container, new Point(e.X, e.Y));
                }
                return;
            }
            int minlen = 25;//节点最小边长
            //鼠标离开
            if (e.X < 0 || e.X > Info.Container.Width || e.Y < 0 || e.Y > Info.Container.Height)
                return;
            //鼠标按下时间过短
            if ((DateTime.Now - Info.LastMouseDownTime).TotalMilliseconds <= 150)
            {
                if (Info.CurrentPointTo != 0 && Info.CurrentPointTo == Info.MouseDownNode)
                {
                    // NodePropertyEditorManager.Show(Info.Page.FindNode(Info.CurrentPointTo),null);
                    Info.IsDragingNode = Info.IsLinkingNode = Info.IsResizingNode = Info.IsDragWorkSpace = false;
                }
                else
                {
                    Info.IsDragingNode = Info.IsLinkingNode = Info.IsResizingNode = Info.IsDragWorkSpace = false;
                    return;
                }
            }
            else if (Info.IsDragingNode)
            {//drag
                var node = Info.Page.FindNode(Info.DragStartNode);
                node.RealRect.X += e.X - Info.DragStartPoint.X;
                node.RealRect.Y += e.Y - Info.DragStartPoint.Y;
                node.LogicRect = ContainerPosToDocPos(node.RealRect);

                //防止越界
                //限制左上角
                node.LogicRect.X = node.LogicRect.X < 0 ? 0 : node.LogicRect.X;
                node.LogicRect.Y = node.LogicRect.Y < 0 ? 0 : node.LogicRect.Y;
                //限制右下角
                node.LogicRect.X = node.LogicRect.X > Info.Page.PaperSize.Width - minlen ? Info.Page.PaperSize.Width - minlen : node.LogicRect.X;
                node.LogicRect.Y = node.LogicRect.Y > Info.Page.PaperSize.Height - minlen ? Info.Page.PaperSize.Height - minlen : node.LogicRect.Y;
                //限制大小
                node.LogicRect.Width = node.LogicRect.X + node.LogicRect.Width > Info.Page.PaperSize.Width ? Info.Page.PaperSize.Width - node.LogicRect.X : node.LogicRect.Width;
                node.LogicRect.Height = node.LogicRect.Y + node.LogicRect.Height > Info.Page.PaperSize.Height ? Info.Page.PaperSize.Height - node.LogicRect.Y : node.LogicRect.Height;

                ReFreshNodeInWindow(node);
                foreach (var line in Info.Page.Lines.Values)
                {
                    if (line.From == node.Id || line.To == node.Id)
                    {
                        line.Points = LineManager.GetLinePoints(
                           Info.Page.FindNode(line.From).LogicRect, line.Anchor1,
                             Info.Page.FindNode(line.To).LogicRect, line.Anchor2);
                        if (line.Points.Length != line.RealPoints.Length)
                            line.RealPoints = new Point[line.Points.Length];
                        ReFreshLineInWindow(line);
                    }
                }
                //tocheck
                SetNeedRedraw(true);
                Info.IsDragingNode = false;
                NodePropertyEditorManager.RefreshPosition();
                Info.Page.IsChanged = true;
            }
            else if (Info.IsLinkingNode)
            {//尝试建立连线
                FCNode node;
                if (Info.CurrentPointTo != 0)
                {
                    node = Info.Page.FindNode(Info.CurrentPointTo);
                    int a;
                    if (IsPointToLinkAblePosotion(new Point(e.X, e.Y), node, out a, false))
                    {
                        if (Info.LinkStartNode != Info.CurrentPointTo || Info.LinkAnchor != a)
                        {
                            var line = new FCLine(Info.LinkStartNode, node.Id, Info.LinkAnchor, a,
                                LineManager.GetLinePoints(Info.Page.FindNode(Info.LinkStartNode).LogicRect, Info.LinkAnchor,
                                node.LogicRect, a),
                                Info.IsLink1
                            );
                            Info.Page.AddLine(line);
                            ReFreshLineInWindow(line);
                            SetNeedRedraw(true);//tocheck
                        }
                        else
                        {
                            //自己连自己 禁止
                        }
                    }
                }
                Info.IsLinkingNode = false;
                Info.Page.IsChanged = true;
            }
            else if (Info.IsResizingNode)
            {

                FCNode node = Info.Page.FindNode(Info.ReSizeNode);
                Rectangle rect = node.RealRect;
                int x, y;
                if (Info.ReSizeAnchor == 1)
                {
                    x = Math.Min(e.X, rect.X + rect.Width - minlen);
                    y = Math.Min(e.Y, rect.Y + rect.Height - minlen);
                    node.RealRect = new Rectangle(x, y, rect.X + rect.Width - x, rect.Y + rect.Height - y);
                }
                else if (Info.ReSizeAnchor == 2)
                {
                    x = Math.Max(e.X, rect.X + minlen);
                    y = Math.Min(e.Y, rect.Y + rect.Height - minlen);
                    node.RealRect = new Rectangle(rect.X, y, x - rect.X, rect.Y + rect.Height - y);
                }
                else if (Info.ReSizeAnchor == 3)
                {
                    x = Math.Max(e.X, rect.X + minlen);
                    y = Math.Max(e.Y, rect.Y + minlen);
                    node.RealRect = new Rectangle(rect.X, rect.Y, x - rect.X, y - rect.Y);
                }
                else if (Info.ReSizeAnchor == 4)
                {
                    x = Math.Min(e.X, rect.X + rect.Width - minlen);
                    y = Math.Max(e.Y, rect.Y + minlen);
                    node.RealRect = new Rectangle(x, rect.Y, rect.X + rect.Width - x, y - rect.Y);
                }
                else
                {
                    throw new Exception();
                }
                node.LogicRect = ContainerPosToDocPos(node.RealRect);
                foreach (var line in Info.Page.Lines.Values)
                {
                    if (line.From == node.Id || line.To == node.Id)
                    {
                        line.Points = LineManager.GetLinePoints(
                            Info.Page.FindNode(line.From).LogicRect, line.Anchor1,
                              Info.Page.FindNode(line.To).LogicRect, line.Anchor2);
                        if (line.Points.Length != line.RealPoints.Length)
                            line.RealPoints = new Point[line.Points.Length];
                        ReFreshLineInWindow(line);
                    }
                }
                SetNeedRedraw(true);
                Info.IsResizingNode = false;
                Info.Page.IsChanged = true;
                NodePropertyEditorManager.RefreshPosition();
            }
            else if (Info.IsDragWorkSpace)
            {//拖拽工作区的可视范围
                //Math.Min限制不能拖到负的位置
                var lp = LeftTop;
                lp.X -= Math.Min(LeftTop.X, (int)((e.X - Info.DragStartPoint.X) / Scale));
                lp.Y -= Math.Min(LeftTop.Y, (int)((e.Y - Info.DragStartPoint.Y) / Scale));
                LeftTop = lp;
                RefreshItemInWindow();
                SetNeedRedraw(true);
                Info.IsDragWorkSpace = false;
            }
        }
        protected virtual void OnMouseUp_Running(object sender, MouseEventArgs e)
        {

        }
        protected virtual void OnMouseOut_NotRunning(object sender, EventArgs e)
        {
            Info.IsLinkingNode = Info.IsDragingNode = Info.IsResizingNode = false;
            Info.IsDragWorkSpace = false;
        }
        protected virtual void OnMouseOut_Running(object sender, EventArgs e)
        {
            Info.IsLinkingNode = Info.IsDragingNode = Info.IsResizingNode = false;
            Info.IsDragWorkSpace = false;
        }



        protected abstract ListViewGroup[] CreatCandidateListGroups();
        private void chartCandidateList_ItemDrag(object sender, ItemDragEventArgs e)
        {
            OnDragFromListView((ListViewItem)e.Item);
            Info.Container.DoDragDrop(e.Item.ToString(), DragDropEffects.Move);
        }
        private void OnDragDrop(object sender, DragEventArgs e)
        {
            Size dfsize = new Size(100, 100);
            Point pos = Info.Container.PointToScreen(new Point(0, 0)); ;//获取容器实际坐标
            pos = ContainerPosToDocPos(e.X - DropDiffer.Width - pos.X - dfsize.Width / 2,
                e.Y - DropDiffer.Height - pos.Y - dfsize.Height / 2);

            FCNode node = null;
            switch (Info.DragType)
            {
                case FCNodeType.Terminal:
                    node = new FCNode(new Rectangle(pos.X, pos.Y, dfsize.Width, dfsize.Height), false, "");
                    break;
                case FCNodeType.Assign:
                    node = new FCNode(new Rectangle(pos.X, pos.Y, dfsize.Width, dfsize.Height), "", "", 0);
                    break;
                case FCNodeType.IF:
                    node = new FCNode(new Rectangle(pos.X, pos.Y, dfsize.Width, dfsize.Height), "", 0, 0);
                    break;
                case FCNodeType.IO:
                    node = new FCNode(new Rectangle(pos.X, pos.Y, dfsize.Width, dfsize.Height), "", true);
                    break;
                case FCNodeType.Label:
                    node = new FCNode(new Rectangle(pos.X, pos.Y, dfsize.Width, dfsize.Height), Info.DragShape, "");
                    break;
                default:
                    break;
            }
            if (node == null)
                return;
            Info.Page.AddNode(node);//todo 更新可见性
            ReFreshNodeInWindow(node);
            Info.CurrentPointTo = node.Id;
            SetNeedRedraw(true);
        }
        protected abstract void OnDragFromListView(ListViewItem item);
        private void OnDragEnter(object sender, DragEventArgs e)
        {
            e.Effect = DragDropEffects.Move;
        }

        public override void Resized()
        {
            if (!Handles.IsResizing)
            {
                RefreshItemInWindow();
                SetNeedRedraw();
            }
        }
        public override void SetActive(bool v)
        {
            base.SetActive(v);
            BindCandidateList(v);
            if (v)
            {
                if (Info.SelectedNode > 0 && !Info.IsRunning())
                {
                    var node = Info.Page.FindNode(Info.SelectedNode);

                    ShowPropertyEditor(node);
                }
            }
            else
            {
                HidePropertyEditor();
            }

        }
        public override void DestoryMgr()
        {
            base.DestoryMgr();
            if (Active)
            {
                SetActive(false);
            }
        }
        void OnNodePropertyChanged(FCNode node, string info)
        {
            if (info == "rect")
            {
                foreach (var line in Info.Page.Lines.Values)
                {
                    if (line.From == node.Id || line.To == node.Id)
                    {
                        line.Points = LineManager.GetLinePoints(
                           Info.Page.FindNode(line.From).LogicRect, line.Anchor1,
                             Info.Page.FindNode(line.To).LogicRect, line.Anchor2);
                        if (line.Points.Length != line.RealPoints.Length)
                            line.RealPoints = new Point[line.Points.Length];
                        ReFreshLineInWindow(line);
                    }
                }
                ReFreshNodeInWindow(node);
            }
            Page.IsChanged = true;
            Drawer.Refresh();
        }
        protected void ShowPropertyEditor(FCNode node)
        {
            NodePropertyEditorManager.Show(node, OnNodePropertyChanged, (f) =>
            {
                if (Handles.GetRightWindow() == f)
                    return;
                Handles.SetRightForm(f, true);
                f.Visible = true;
            });
        }
        protected void HidePropertyEditor()
        {
            NodePropertyEditorManager.Show(null, OnNodePropertyChanged, (f) =>
            {
                if (Handles.GetRightWindow() != f)
                    return;
                Handles.SetRightForm(f, false);
                f.Visible = false;
            });
        }

        protected object Locker = new object();
        protected bool NeedRedraw;
        public virtual void SetNeedRedraw(bool tf = true)
        {
            lock (Locker)
            {
                if (tf)
                {
                    NeedRedraw = true;
                }
                else
                {
                    NeedRedraw = false;
                }
            }
        }
        public override void Every33ms()
        {
            lock (Locker)
            {
                if (NeedRedraw)
                {
                    SetNeedRedraw(false);
                    RefreshItemInWindow();
                    Drawer.Refresh();
                }
            }
        }

        protected virtual void RefreshItemInWindow()
        {
            //计算可见的节点
            Size size = Info.Container.Size;
            foreach (var node in Info.Page.Nodes.Values)
                ReFreshNodeInWindow(node);
            //计算可见的线段
            foreach (var line in Info.Page.Lines.Values)
                ReFreshLineInWindow(line);
        }
        protected void ReFreshNodeInWindow(FCNode node)
        {
            Size size = Info.Container.ClientSize;//todo  Size OR ClientSize
            Rectangle rect = node.RealRect = DocPosToContainerPos(node.LogicRect);
            node.IsInWindow = (Utility.Between(rect.X, -rect.Width, size.Width) &&
              Utility.Between(rect.Y, -rect.Height, size.Height));
        }
        protected void ReFreshLineInWindow(FCLine line)
        {
            Size size = Info.Container.ClientSize;//todo  Size OR ClientSize
            line.IsInWindow = false;
            for (int j = 0; j < line.Points.Length; j++)
            {
                var point = line.Points[j];
                line.RealPoints[j] = DocPosToContainerPos(point);
                if (!line.IsInWindow && Utility.Between(line.RealPoints[j].X, 0, size.Width)
                     && Utility.Between(line.RealPoints[j].Y, 0, size.Height))
                {
                    line.IsInWindow = true;
                }
            }
        }
    }
    internal class ViewManager_Info
    {
        //常量
        public int LinkAbleCycleR;


        //基础信息
        public FCWorkPageBase Page;
        internal Control Container;
        internal Point LeftTop;
        public float Scale;
        //运行信息
        public Func<bool> IsRunning;
        public object Runner;
        //鼠标交互信息
        public Point MousePosition;
        public int CurrentPointTo;//鼠标当前指向的node
        public DateTime LastMouseDownTime;
        public bool IsDragingNode = false, IsLinkingNode = false, IsResizingNode = false;//正在进行的鼠标操作
        public bool CanDragingNode = false, CanLinkNode = false, CanResizeNode = false;//点击可以进行的鼠标操作
        public int LinkAnchor;//鼠标连线的开始节点的锚点
        public int ReSizeAnchor;//鼠标调整大小的节点的锚点从左上顺时针1-4
        public Point DragStartPoint;
        public int MouseDownNode;
        public int DragStartNode => MouseDownNode;
        public int LinkStartNode => MouseDownNode;//鼠标连线开始的节点
        public int ReSizeNode => MouseDownNode;//鼠标调整大小的节点
        public int RightClickNode => MouseDownNode;
        public bool CanDragWorkSpace = false, IsDragWorkSpace = false;

        public int HighLightNode;
        public int SelectedNode;
        //拖拽信息
        public FCNodeType DragType;
        public Shape DragShape;

        public Action Drawed;
        public bool IsLink1;

        public ViewManager_Info()
        {
            Page = null;
            Container = null;
            Scale = 1;
            LeftTop = new Point(0, 0);
        }
    }
}
